import 'package:flutter/cupertino.dart' show CupertinoButton, ShapeBorder, CupertinoColors;
import 'package:flutter/material.dart';

import '../base_stateless_widget.dart';

/// BaseButton
/// use CupertinoButton or CupertinoButton.filled by cupertino
/// *** use cupertino = { forceUseMaterial: true } force use MaterialButton or TextButton or OutlinedButton or ElevatedButton on cuperitno.
/// use MaterialButton or TextButton or OutlinedButton or ElevatedButton by material
/// *** use material = { forceUseCupertino: true } force use CupertinoButton or CupertinoButton.filled on material.
class BaseButton extends BaseStatelessWidget {
  const BaseButton({
    Key? baseKey,
    this.key,
    this.color,
    this.onPressed,
    this.disabledColor,
    this.padding,
    this.child,
    this.minSize = 44.0,
    this.pressedOpacity = 0.1,
    this.borderRadius = const BorderRadius.all(Radius.circular(8.0)),
    this.filled = false,
    this.onLongPress,
    this.onHighlightChanged,
    this.textTheme,
    this.textColor,
    this.disabledTextColor,
    this.focusColor,
    this.hoverColor,
    this.highlightColor,
    this.splashColor,
    this.colorBrightness,
    this.elevation,
    this.focusElevation,
    this.highlightElevation,
    this.disabledElevation,
    this.visualDensity,
    this.shape,
    this.clipBehavior = Clip.none,
    this.focusNode,
    this.autofocus = false,
    this.materialTapTargetSize,
    this.animationDuration,
    this.minWidth,

    /// 使按钮跟CupertinoButton的一样高，只有MaterialButton有效
    /// 其他的需修改Theme.of(context).buttonTheme.height才有效
    this.height = 48.0,
    this.flat = false,
    this.outline = false,
    this.borderSide,
    this.disabledBorderColor,
    this.highlightedBorderColor,
    this.raised = false,
    Map<String, Object>? cupertino,
    Map<String, Object>? material,
  }) : super(key: baseKey, cupertino: cupertino ?? const <String, Object>{}, material: material ?? const <String, Object>{});

  /// [CupertinoButton], child is Row(children:[icon, label])
  /// or
  /// [MaterialButton], child is Row(children:[icon, label])
  /// or
  /// [TextButton.icon]
  /// or
  /// [OutlinedButton.icon]
  /// or
  /// [ElevatedButton.icon]
  BaseButton.icon({
    Key? baseKey,
    this.key,
    this.color,
    this.onPressed,
    this.disabledColor,
    this.padding,
    this.minSize = 44.0,
    this.pressedOpacity = 0.4,
    this.borderRadius = const BorderRadius.all(Radius.circular(8.0)),
    this.filled = false,
    this.onLongPress,
    this.onHighlightChanged,
    this.textTheme,
    this.textColor,
    this.disabledTextColor,
    this.focusColor,
    this.hoverColor,
    this.highlightColor,
    this.splashColor,
    this.colorBrightness,
    this.elevation,
    this.focusElevation,
    this.highlightElevation,
    this.disabledElevation,
    this.visualDensity,
    this.shape,
    this.clipBehavior = Clip.none,
    this.focusNode,
    this.autofocus = false,
    this.materialTapTargetSize,
    this.animationDuration,
    this.minWidth,
    // 使按钮跟CupertinoButton的一样高
    this.height = 48.0,
    this.flat = false,
    this.outline = false,
    this.borderSide,
    this.disabledBorderColor,
    this.highlightedBorderColor,
    this.raised = false,

    /// use TextButton.icon or OutlinedButton.icon or ElevatedButton.icon.
    /// if do not want to have label, use BaseIconButton.
    required Widget icon,
    Widget? label,
    double interval = 8.0,
    Map<String, dynamic>? cupertino,
    Map<String, dynamic>? material,
  })  : child = label != null
      ? Row(
    mainAxisSize: MainAxisSize.min,
    children: <Widget>[
      icon,
      SizedBox(width: interval),
      label,
    ],
  )
      : icon,
        super(key: baseKey, cupertino: cupertino ?? <String, dynamic>{}, material: material ?? <String, dynamic>{});

  /// *** general properties start ***

  @override
  final Key? key;

  /// [CupertinoButton.color]
  /// or
  /// [MaterialButton.color]
  final Color? color;

  /// [CupertinoButton.onPressed]
  /// or
  /// [MaterialButton.onPressed]
  final VoidCallback? onPressed;

  /// [CupertinoButton.disabledColor]
  /// or
  /// [MaterialButton.disabledColor]
  final Color? disabledColor;

  /// [CupertinoButton.padding]
  /// or
  /// [MaterialButton.padding]
  final EdgeInsetsGeometry? padding;

  /// [CupertinoButton.child]
  /// or
  /// [MaterialButton.child]
  final Widget? child;

  /// *** general properties end ***

  /// *** cupertino properties start ***

  /// [CupertinoButton.minSize]
  final double minSize;

  /// [CupertinoButton.pressedOpacity]
  final double pressedOpacity;

  /// [CupertinoButton.borderRadius]
  final BorderRadius borderRadius;

  /// [CupertinoButton.filled]
  /// use CupertinoButton.filled, will ignore the color, use primary color.
  final bool filled;

  /// *** cupertino properties ened ***

  /// *** material properties start ***

  /// [MaterialButton.onLongPress]
  final VoidCallback? onLongPress;

  /// [MaterialButton.onHighlightChanged]
  final ValueChanged<bool>? onHighlightChanged;

  /// [MaterialButton.textTheme]
  final ButtonTextTheme? textTheme;

  /// [MaterialButton.textColor]
  final Color? textColor;

  /// [MaterialButton.disabledTextColor]
  final Color? disabledTextColor;

  /// [MaterialButton.focusColor]
  final Color? focusColor;

  /// [MaterialButton.hoverColor]
  final Color? hoverColor;

  /// [MaterialButton.highlightColor]
  final Color? highlightColor;

  /// [MaterialButton.splashColor]
  final Color? splashColor;

  /// [MaterialButton.colorBrightness]
  final Brightness? colorBrightness;

  /// [MaterialButton.elevation]
  final double? elevation;

  /// [MaterialButton.focusElevation]
  final double? focusElevation;

  /// [MaterialButton.highlightElevation]
  final double? highlightElevation;

  /// [MaterialButton.disabledElevation]
  final double? disabledElevation;

  /// [MaterialButton.visualDensity]
  final VisualDensity? visualDensity;

  /// [MaterialButton.shape]
  final OutlinedBorder? shape;

  /// [MaterialButton.clipBehavior]
  final Clip clipBehavior;

  /// [MaterialButton.focusNode]
  final FocusNode? focusNode;

  /// [MaterialButton.autofocus]
  final bool autofocus;

  /// [MaterialButton.materialTapTargetSize]
  final MaterialTapTargetSize? materialTapTargetSize;

  /// [MaterialButton.animationDuration]
  final Duration? animationDuration;

  /// [MaterialButton.minWidth]
  final double? minWidth;

  /// [MaterialButton.height]
  final double height;

  /// [TextButton]
  /// use TextButton
  final bool flat;

  /// [OutlinedButton]
  /// use OutlinedButton
  final bool outline;

  /// [OutlinedButton.borderSide]
  final BorderSide? borderSide;

  /// [OutlinedButton.disabledBorderColor]
  final Color? disabledBorderColor;

  /// [OutlinedButton.highlightedBorderColor]
  final Color? highlightedBorderColor;

  /// [ElevatedButton]
  /// use ElevatedButton
  final bool raised;

  /// *** material properties end ***

  @override
  Widget buildByCupertino(BuildContext context) {
    final Color? _disabledColor = valueFromCupertino('disabledColor', disabledColor) ?? CupertinoColors.quaternarySystemFill;
    if (filled) {
      return CupertinoButton.filled(
        key: valueFromCupertino('key', key),
        child: valueFromCupertino('child', child) ?? const SizedBox(),
        padding: valueFromCupertino('padding', padding) ?? EdgeInsets.zero,
        disabledColor: _disabledColor ?? CupertinoColors.quaternarySystemFill,
        minSize: valueFromCupertino('minSize', minSize) ?? 44.0,
        pressedOpacity: valueFromCupertino('pressedOpacity', pressedOpacity) ?? 0.1,
        borderRadius: valueFromCupertino('borderRadius', borderRadius) ?? const BorderRadius.all(Radius.circular(8.0)),
        onPressed: valueFromCupertino('onPressed', onPressed),
      );
    }
    return CupertinoButton(
      key: valueFromCupertino('key', key),
      child: valueFromCupertino('child', child) ?? const SizedBox(),
      padding: valueFromCupertino('padding', padding) ?? EdgeInsets.zero,
      color: valueFromCupertino('color', color),
      disabledColor: _disabledColor ?? CupertinoColors.quaternarySystemFill,
      minSize: valueFromCupertino('minSize', minSize) ?? 44.0,
      pressedOpacity: valueFromCupertino('pressedOpacity', pressedOpacity) ?? 0.1,
      borderRadius: valueFromCupertino('borderRadius', borderRadius) ?? const BorderRadius.all(Radius.circular(8.0)),
      onPressed: valueFromCupertino('onPressed', onPressed),
    );
  }

  @override
  Widget buildByMaterial(BuildContext context) {
    assert(
    (!flat && !outline && !raised) ||
        (flat && !outline && !raised) ||
        (!flat && outline && !raised) ||
        (!flat && !outline && raised),
    'flat and outline can not be true at the same time.',
    );

    if (flat == true) {
      return TextButton(
        key: valueFromMaterial('key', key),
        onPressed: valueFromMaterial('onPressed', onPressed),
        onLongPress: onLongPress,
        style: TextButton.styleFrom(
          textStyle: _getTextStyle(textTheme),
          foregroundColor: textColor,
          disabledForegroundColor: disabledTextColor,
          backgroundColor: valueFromMaterial('color', color),
          disabledBackgroundColor: valueFromMaterial('disabledColor', disabledColor),
          shadowColor: focusColor,
          elevation: elevation ?? 0,
          padding: valueFromMaterial('padding', padding) ?? const EdgeInsets.all(16.0),
          minimumSize: Size(minWidth ?? 0, height),
          side: borderSide,
          shape: shape,
          visualDensity: visualDensity,
          tapTargetSize: materialTapTargetSize,
          animationDuration: animationDuration ?? const Duration(milliseconds: 200),
        ),
        focusNode: focusNode,
        autofocus: autofocus,
        clipBehavior: clipBehavior,
        child: valueFromMaterial('child', child) ?? const SizedBox(),
      );
    } else if (outline) {
      return OutlinedButton(
        key: valueFromMaterial('key', key),
        onPressed: valueFromMaterial('onPressed', onPressed),
        onLongPress: onLongPress,
        style: OutlinedButton.styleFrom(
          textStyle: _getTextStyle(textTheme),
          foregroundColor: textColor,
          disabledForegroundColor: disabledTextColor,
          backgroundColor: valueFromMaterial('color', color),
          shadowColor: focusColor,
          elevation: elevation ?? 0,
          padding: valueFromMaterial('padding', padding) ?? const EdgeInsets.all(16.0),
          minimumSize: Size(minWidth ?? 0, height),
          side: borderSide,
          shape: shape,
          visualDensity: visualDensity,
          tapTargetSize: materialTapTargetSize,
          animationDuration: animationDuration ?? const Duration(milliseconds: 200),
        ),
        focusNode: focusNode,
        autofocus: autofocus,
        clipBehavior: clipBehavior,
        child: valueFromMaterial('child', child) ?? const SizedBox(),
      );
    } else if (raised) {
      return ElevatedButton(
        key: valueFromMaterial('key', key),
        onPressed: valueFromMaterial('onPressed', onPressed),
        onLongPress: onLongPress,
        style: ElevatedButton.styleFrom(
          textStyle: _getTextStyle(textTheme),
          foregroundColor: textColor,
          disabledForegroundColor: disabledTextColor,
          backgroundColor: valueFromMaterial('color', color),
          disabledBackgroundColor: valueFromMaterial('disabledColor', disabledColor),
          shadowColor: focusColor,
          elevation: elevation ?? 0,
          padding: valueFromMaterial('padding', padding) ?? const EdgeInsets.all(16.0),
          minimumSize: Size(minWidth ?? 0, height),
          side: borderSide,
          shape: shape,
          visualDensity: visualDensity,
          tapTargetSize: materialTapTargetSize,
          animationDuration: animationDuration ?? const Duration(milliseconds: 200),
        ),
        focusNode: focusNode,
        autofocus: autofocus,
        clipBehavior: clipBehavior,
        child: valueFromMaterial('child', child) ?? const SizedBox(),
      );
    }

    // MaterialButton is deprecated, use TextButton instead
    return TextButton(
      key: valueFromMaterial('key', key),
      onPressed: valueFromMaterial('onPressed', onPressed),
      onLongPress: onLongPress,
      style: TextButton.styleFrom(
        textStyle: _getTextStyle(textTheme),
        foregroundColor: textColor,
        disabledForegroundColor: disabledTextColor,
        backgroundColor: valueFromMaterial('color', color),
        disabledBackgroundColor: valueFromMaterial('disabledColor', disabledColor),
        shadowColor: focusColor,
        elevation: elevation ?? 0,
        padding: valueFromMaterial('padding', padding) ?? const EdgeInsets.all(16.0),
        minimumSize: Size(minWidth ?? 0, height),
        side: borderSide,
        shape: shape,
        visualDensity: visualDensity,
        tapTargetSize: materialTapTargetSize,
        animationDuration: animationDuration ?? const Duration(milliseconds: 200),
      ),
      focusNode: focusNode,
      autofocus: autofocus,
      clipBehavior: clipBehavior,
      child: valueFromMaterial('child', child) ?? const SizedBox(),
    );
  }

  TextStyle? _getTextStyle(ButtonTextTheme? textTheme) {
    switch (textTheme) {
      case ButtonTextTheme.normal:
        return const TextStyle(fontSize: 14, fontWeight: FontWeight.normal);
      case ButtonTextTheme.accent:
        return const TextStyle(fontSize: 14, fontWeight: FontWeight.w500);
      case ButtonTextTheme.primary:
        return const TextStyle(fontSize: 16, fontWeight: FontWeight.bold);
      default:
        return null;
    }
  }
}